package cn.tedu.charging.order.amqp;

import cn.tedu.charging.common.constant.CacheKeyConst;
import cn.tedu.charging.common.pojo.message.DelayCheckMessage;
import cn.tedu.charging.order.service.ConsumerService;
import com.alibaba.fastjson2.JSON;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 当前项目准备的rabbitmq的消费入口
 */
@Component
@Slf4j
public class AmqpConsumer {
    @Autowired
    private ConsumerService consumerService;
    //单独创建方法 监听延迟死信队列
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 1.消费入口 解析参数 DelayCheckMessage
     * 2.调用业务层完成业务逻辑
     * 3.确认反馈
     *
     * @param json
     * @param message
     * @param channel
     */
    @RabbitListener(queues = "dlx_q")
    public void consumeDelay(String json, Message message, Channel channel) {
        log.info("拿到延迟消息:" + json);
        DelayCheckMessage delayMessage = JSON.parseObject(json, DelayCheckMessage.class);
        ValueOperations valueOps = redisTemplate.opsForValue();
        //1.设计一个锁的key值,和订单有关
        String lockKey = "charging:order:consume:lock:" + delayMessage.getOrderNo();
        //2.使用do while循环抢锁
        Boolean haveLock = false;
        int count = 0;//重抢次数的计数器
        try {
            do {
                //所有线程进入到do都要先抢锁 setnx key value ex 5
                if (count == 0) {
                    log.debug("第一次抢锁,直接抢");
                    haveLock = valueOps.setIfAbsent(lockKey, "", 5, TimeUnit.SECONDS);
                } else if (count < 4) {
                    log.debug("第{}次抢锁,失败,正在重试", count + 1);
                    Thread.sleep(200);
                    haveLock = valueOps.setIfAbsent(lockKey, "", 5, TimeUnit.SECONDS);
                } else {
                    log.error("已经抢锁4次以上,不允许重抢");
                    break;
                }
                //计数器+1
                count++;
            } while (!haveLock);
            //3.抢锁成功haveLock=true
            consumerService.handleCheckNoRes(delayMessage);
        } catch (Exception e) {
            log.error("处理延迟消息异常", e);
        } finally {
            //4.执行完业务 需要释放锁
            redisTemplate.delete(lockKey);
        }
        try {
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("确认消息异常", e);
        }
    }
}
